﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;



public class GameObjectPool : MonoBehaviour
{
    private static GameObjectPool instance;


    public static void SetMaxPoolCount(int maxCount)
    {
        GetInstance().maxCount = maxCount;
    }
    
    #region "Static load GameObject from resources buffer"
    public static GameObject LoadGameObject(string path, Vector3 position, Quaternion rotation)
    {
        var result = LoadGameObject(path);
        return result;
    }

    public static GameObject LoadGameObject(string path,bool active)
    {
        var result = LoadGameObject(path);
        result.SetActive(active);

        return result;
    }

    public static GameObject LoadGameObject(string Path)
    {
        var instance = GetInstance();
        
        var pool = instance.GetPoolFromPools(Path);
        var resources = instance.GetObjectFromPool(pool,Path);

        return resources;
    }
    #endregion


    public static GameObject LoadFromInstance(GameObject resources)
    {
        if(resources == null)
            return null;

        string path = resources.name;
        if(path.Contains("(Clone)"))
            Debug.LogError("在对象池内实例的对象名字包含(Clone),请检查对象是否被复制。对象是:"+resources.name);

        var poolInstance = GetInstance();

        var pool = poolInstance.GetPoolFromPools(path);
        var loadedResouces = poolInstance.GetObjectFromPool(pool,resources);
        
        return loadedResouces;
    }



    private static GameObjectPool GetInstance()
    {
        if(!instance)
        {
            var instanceObj = new GameObject();
            DontDestroyOnLoad(instanceObj);

            instance = instanceObj.AddComponent<GameObjectPool>();
            instance.name = "GameObjectPool";
        }

        return instance;
    }




    private Dictionary<string,List<InstanceInPool>> pools = new Dictionary<string, List<InstanceInPool>>();
    private int maxCount = 100;



    private List<InstanceInPool> GetPoolFromPools(string ID)
    {
        if(pools.ContainsKey(ID))
            return pools[ID];
        else
        {
            var pool = new List<InstanceInPool>();
            pools.Add(ID,pool);

            return pool;
        }   
    }

    private GameObject GetObjectFromPool(List<InstanceInPool> pool,string path)
    {
        var gotObj = FindFreeInstanceInPool(pool,()=>
        {
            return Instantiate(ResourcesBuffer.Load<GameObject>(path));
        });
        return gotObj;
    }

    private GameObject GetObjectFromPool(List<InstanceInPool> pool,GameObject resource)
    {
        var gotObj = FindFreeInstanceInPool(pool,()=>
        {
            return Instantiate(resource);
        });
        return gotObj;
    }



    private GameObject FindFreeInstanceInPool(List<InstanceInPool> pool,GetGameObjAction createAction)
    {
        for(int i = 0;i<pool.Count;i++)
        {
            var selected = pool[i];

            if(selected.GameObject==null)
            {
                pool.Remove(selected);
                continue;
            }

            selected.TryPushInstanceInPool();
            if(!selected.IsEnable)
            {
                selected.IsEnable = true;
                return selected.GameObject;
            }
        }

        var createdWhenPoolNotenough = TryToCreateGameObjInPool(pool,createAction);
        return createdWhenPoolNotenough;
    }


    private GameObject TryToCreateGameObjInPool(List<InstanceInPool> pool,GetGameObjAction createAction)
    {
        if(CheckFullPool(pool))
            return null;
        else
        {
            var loadedObject = createAction();
            var created = InstanceInPool.CreateInstance(loadedObject,true);
            pool.Add(created);

            return created.GameObject;
        }
    }

    private bool CheckFullPool(List<InstanceInPool> pool)
    {
        var isLenEqualZero = maxCount == 0;
        var isPoolFull = pool.Count<maxCount;

        var result = isLenEqualZero||isPoolFull;
        if(!result)
            Debug.Log("对象池已满!现在返回空值!对象池是否达到最大值？ " + !isPoolFull+" 对象池是否被关闭？ " + isLenEqualZero);

        return !result;
    } 


    private delegate GameObject GetGameObjAction();
}
